﻿using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace CDude.Tools
{
    internal class DevicePlugEventArgs : EventArgs
    {
        public DevicePlugEventArgs(bool added)
        {
            this.Added = added;
        }

        public bool Added { get; private set; }
    }

    internal class DevicePlugNotifier
    {
        private Form form;

        public unsafe DevicePlugNotifier(Form form)
        {
            this.form = form;

            DEV_BROADCAST_DEVICEINTERFACE dev_broadcast_deviceinterface = new DEV_BROADCAST_DEVICEINTERFACE(Guid.Empty);
            NativeMethods.RegisterDeviceNotificationW(form.Handle, (IntPtr)(&dev_broadcast_deviceinterface), 4);
        }

        public event EventHandler<DevicePlugEventArgs> DeviceChanged;

        public event EventHandler NoDataDeviceChanged;

        public unsafe void WndProc(ref Message m)
        {
            if (m.Msg == 0x219)
            {
                if ((int)m.WParam == 0x8000 || (int)m.WParam == 0x8004)
                {
                    DEV_BROADCAST_DEVICEINTERFACE* lParam = (DEV_BROADCAST_DEVICEINTERFACE*)m.LParam;
                    if (lParam->dbch_devicetype == 5 && Marshal.PtrToStringUni((IntPtr)(&lParam->dbcc_name)).ToUpper().Contains(@"\USB#VID_054C&PID_069B#"))
                        DeviceChanged(this, new DevicePlugEventArgs((int)m.WParam == 0x8000));
                }
                else if ((int)m.WParam == 7)
                    NoDataDeviceChanged(this, new EventArgs());
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct DEV_BROADCAST_DEVICEINTERFACE
        {
            public Guid dbcc_classguid;
            public char dbcc_name;
            public int dbch_devicetype;
            public int dbch_size;
            private int dbch_reserved;

            public DEV_BROADCAST_DEVICEINTERFACE(Guid classGuid)
            {
                this.dbch_size = Marshal.SizeOf(typeof(DEV_BROADCAST_DEVICEINTERFACE));
                this.dbch_devicetype = 5;
                this.dbch_reserved = 0;
                this.dbcc_classguid = classGuid;
                this.dbcc_name = '\0';
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct DEV_BROADCAST_HEADER
        {
            public int dbch_devicetype;
            public int dbch_reserved;
            public int dbch_size;
        }
    }
}